import { localStorage } from "@/utils/storage";
import { getToken } from "@/utils/token";
import { pageToLogin } from "@/utils/utils";
interface UniRequestConfig extends Partial<UniApp.RequestOptions> {
  baseUrl?: string;
}

interface UniResponse extends UniApp.RequestSuccessCallbackResult {
  success?: boolean;
  errCode?: number;
  errMsg?: string;
  config?: UniRequestConfig;
}

type DataType = UniApp.RequestOptions["data"];
type HeaderType = UniApp.RequestOptions["header"];
type UniRequestInterceptor = (options: UniApp.RequestOptions) => UniApp.RequestOptions;
type UniResponseInterceptor = (
  response: UniApp.RequestSuccessCallbackResult,
) => UniApp.RequestSuccessCallbackResult;
type UniResponseErrorInterceptor = (
  err: UniApp.GeneralCallbackResult,
) => UniApp.GeneralCallbackResult;

class Http {
  // 配置
  private config: UniRequestConfig = { header: { "Content-Type": "application/json" } };

  // 请求拦截器数组
  private requestInterceptors = [] as UniRequestInterceptor[];

  // 响应拦截器
  private responseInterceptors = [] as UniResponseInterceptor[];

  // 响应错误拦截器
  private responseErrorInterceptors = [] as UniResponseErrorInterceptor[];

  // 是否刷新 token
  public isRefresh = true;

  // 重试队列
  public requestQueue: (() => void)[] = [];

  // 拦截器
  public interceptors = {
    request: {
      use: (req: UniRequestInterceptor) => {
        this.requestInterceptors.push(req);
      },
    },
    response: {
      use: (res: UniResponseInterceptor, err: UniResponseErrorInterceptor) => {
        this.responseInterceptors.push(res);
        this.responseErrorInterceptors.push(err);
      },
    },
  };

  constructor(config: Partial<UniRequestConfig> = {}) {
    // 合并配置参数
    this.config = Object.assign(this.config, config);
  }
  public request(config: UniRequestConfig): Promise<UniResponse> {
    return new Promise((resolve, reject) => {
      let {
        baseUrl = this.config.baseUrl || "",
        url,
        method = "GET",
        header = {},
        timeout = this.config.timeout,
        data,
        ...rest
      } = config;
      url = baseUrl + url;
      header = Object.assign(this.config.header, header);
      let options: UniApp.RequestOptions = {
        url,
        method,
        header,
        timeout,
        data,
        success: (res: UniResponse) => {
          res.config = config;
          // 执行响应拦截
          for (let ri of this.responseInterceptors) {
            res = ri(res);
          }
          resolve(res);
        },
        fail: (err) => {
          // 执行响应错误拦截
          for (let ei of this.responseErrorInterceptors) {
            err = ei(err);
          }
          reject(err);
        },
        ...rest,
      };

      // 执行请求拦截器
      for (let ri of this.requestInterceptors) {
        options = ri(options);
      }
      // 发送请求
      uni.request(options);
    });
  }
}

const DURATION = 10000; // 超时时间
const service = new Http({
  baseUrl: "/", // 基础路径
  timeout: DURATION,
});

// 添加请求拦截器
service.interceptors.request.use((options) => {
  console.log("interceptors.request参数：");
  console.log(options);
  if (uni.getStorageSync("token")) {
    options.header["Authorization"] = "Bearer " + uni.getStorageSync("token");
  }
  return options;
});

// 添加响应拦截器
service.interceptors.response.use(
  (response: UniResponse) => {
    console.log("interceptors.response响应体：");
    console.log(response);

    // 登录状态失效，重新登录
    if (response.statusCode == 401) {
      // 防止重复获取
      if (!service.isRefresh) {
        service.isRefresh = true;

        // 拿到token
        getToken().then(() => {
          // 开始执行队列请求
          service.requestQueue.forEach((cb) => cb());

          // 重试完了清空这个队列
          service.requestQueue = [];
          service.isRefresh = false;

          // 重新执行本次请求
          return service.request(response.config || {});
        });
      } else {
        new Promise((resolve) => {
          service.requestQueue.push(() => {
            resolve(service.request(response.config || {}));
          });
        });
      }
    } else if (response.statusCode == 403) {
      localStorage.remove("token");
      pageToLogin();
    }

    if (response.statusCode !== 200 && response.errMsg) {
      uni.showToast({
        title: response.errMsg,
      });
    }

    return response;
  },
  (err) => {
    return err;
  },
);

export async function request(options: UniApp.RequestOptions) {
  return await service.request(options).then((res) => res.data);
}

export async function get(url: string, data: DataType = "", header: HeaderType = {}) {
  return request({ method: "GET", url, data, header });
}

export async function post(url: string, data: DataType = "", header: HeaderType = {}) {
  return request({ method: "POST", url, data, header });
}

export async function put(url: string, data: DataType = "", header: HeaderType = {}) {
  return request({ method: "PUT", url, data, header });
}
